package com.wtgroup.demo.面试题;

import com.wtgroup.demo.common.util.SleepUtil;

import java.util.LinkedList;

/**
 * @author dafei
 * @version 0.1
 * @date 2021/3/7 22:00
 */
public class Q002 {
    /**
     * 写一个固定容量同步容器, 拥有 put 和 get 方法, 以及 getCount 方法.
     * 能够支持 2 个生产者线程和 10 个消费者线程的阻塞调用.
     *
     * Note:
     * M1) wait/notifyAll 实现. 不推荐. 这种方式, 消费者和生产者在一个等待队列里, 多消费者生产者时. 假如生产者A始终唤醒的是其他生产者, 那么消费者永远得不到执行.
     * M2) Condition 实现. (推荐)
     */


    public static void main(String[] args) {
        MyContainer myContainer = new MyContainer();

        for (int i = 0; i < 2; i++) {
            int finalI = i;
            new Thread(() -> {
                while (true) {
                    myContainer.put(finalI);
                    SleepUtil.sleep(1);
                }
            }).start();
        }

        for (int j = 0; j < 10; j++) {
            new Thread(() -> {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " " + myContainer.get());
                }
            }).start();
        }

        SleepUtil.sleep(100);
    }


    public static class MyContainer<T> {

        private LinkedList<T> list = new LinkedList<>(); // 队列用 link 更好
        public static final int MAX_CAP = 10; // 固定容量

        public synchronized T get() {
            while (list.size() == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            T head = list.removeFirst();
            // 通知生产者们可以生产了
            this.notifyAll();
            return head;
        }

        public synchronized void put(T item) {
            while (list.size() == MAX_CAP) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            list.addLast(item); // === add
            this.notifyAll();
        }
    }

}
